#pragma once
#include "observer.h"

namespace krryn{
namespace gui{
	class window;
	class button;
	class progress_bar;
	class tree_view;

	window *create_window();

	class gui_exception{
	public:
		gui_exception(const std::string &a_String) {}
	};

	class widget{
	public:
		widget(widget *a_Parent = 0) : m_Parent(a_Parent) {}

		virtual ~widget() {}

		virtual void add_child(widget *a_Child){
			throw gui_exception("Can't nest children for this widget");
		}

		virtual void do_layout() {}

		// these are here so the render control might choose a different gui layout
		// or toolkit than the native controls
		virtual button *create_button(){
			if(m_Parent){
				return m_Parent->create_button();
			}else{
				throw gui_exception("Can't create button");
			}
		}

		virtual progress_bar *create_progress_bar(){
			if(m_Parent){
				return m_Parent->create_progress_bar();
			}else{
				throw gui_exception("Can't create progress bar");
			}
		}

		virtual tree_view *create_tree_view(){
			if(m_Parent){
				return m_Parent->create_tree_view();
			}else{
				throw gui_exception("Can't create tree view");
			}
		}

		virtual void set_size(int a_Width, int a_Height) = 0;
		virtual void set_position(int a_X, int a_Y) = 0;
		virtual void set_parent(widget *a_Parent){ m_Parent = a_Parent; }
	protected:

		widget *m_Parent;
	};

	class window : public widget{
	public:
		window() : widget() {}

		virtual void run(){
			m_Parent->do_layout();
		}

		virtual void start(){
			// assign to parent so that all the create_* functions will
			// recurse to the concrete window instead of this one which would
			// throw exceptions because we're not giving them anything.
			m_Parent = m_Concrete = create_window();
			init();
			show();
		}

		virtual void init() {}

		virtual void add_child(widget *a_Child){
			a_Child->set_parent(m_Parent);
			a_Child->do_layout();
		}

		virtual void set_caption(const std::string &a_Caption){
			m_Concrete->set_caption(a_Caption);
		}

		virtual void set_size(int a_Width, int a_Height){
			m_Concrete->set_size(a_Width, a_Height);
		}

		virtual void set_position(int a_X, int a_Y){
			m_Concrete->set_position(a_X, a_Y);
		}

		virtual void show(){
			m_Concrete->show();
		}
	private:
		window *m_Concrete;
	};

	class button : public widget{
	public:
		button(widget *a_Parent) : widget(a_Parent) {}

		core::subject<core::basic_args*> m_OnClick;

		virtual void set_caption(const std::string &a_Text) = 0;
	};

	class progress_bar : public widget{
	public:
		progress_bar(widget *a_Parent) : widget(a_Parent) {}

		virtual void set_range(int a_Begin, int a_End) = 0;
		virtual void set_progress(int a_Progress) = 0;
	};

	class tree_view_node{
	public:
		std::string m_Key;
		std::string m_Title;

		tree_view_node(const std::string &a_Key) : m_Key(a_Key), m_Title("") {}
		tree_view_node(const std::string &a_Key, const std::string &a_Title) : m_Key(a_Key), m_Title(a_Title) {}
	};

	class tree_view : public widget{
	public:
		tree_view(widget *a_Parent) : widget(a_Parent) {}

		virtual void add_node(tree_view_node *a_Node, const std::string &a_ParentKey = "") = 0;
	};
}
}